export = {}
interface Bird {
  fly();
  layEggs();
}

interface Fish {
  swim();
  layEggs();
}

function getSmallPet(): Fish | Bird {
  // ...
  return
}
let pet = getSmallPet();

/*
if ((<Fish>pet2).swim) {
  (<Fish>pet2).swim();
}
else {
  (<Bird>pet2).fly();
}
*/


/** 类型保护机制type guard*/
//在上一节最后的例子中 我们不得不多次使用类型断言
//很烦,不是我们所期望的,我们期望
//假若我们一旦检查过类型，就能在之后的每个分支里清楚地知道 pet的类型
// TypeScript里的 类型保护机制就让它成为了现实

/** 类型保护就是一些【表达式】，它们会在运行时检查以确保在某个作用域里的类型。*/

/** 法一. Using type predicates(类型谓词)*/
// 要定义一个类型保护，我们只要简单地定义一个函数，它的返回值是一个 类型谓词(`type predicates`)：
// parameterName is Type
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
/*↑
在这个例子里， pet is Fish就是类型谓词。
谓词为 parameterName is Type 这种形式，
parameterName必须是来自于当前函数签名里的一个参数名。*/

/*
如果不使用这个is 那么我们在调用此函数后的判断里 也没法点出对应的值
因为我们没法确定我们是返回true的时候说明是Fish还是返回false的时候

虽然js是知道的, 但也是真正运行的时候, 而我们的ts不会运行js

SO 需要 is 来声明该函数执行如果为true的时候其应该是 xxx 类型, 这样我们才能在对应的if else 体内点出对应的东西
*/



// ↓使用了类型保护后,'swim' 和 'fly' 调用都没有问题了
//Any time isFish is called with some variable, TypeScript will narrow that variable to that specific type if the original type is compatible.
if (isFish(pet)) {
  pet.swim();
}
else {
  pet.fly();
}
//Notice that TypeScript not only knows that pet is a Fish in the if branch; it also knows that in the else branch, you don’t have a Fish, so you must have a Bird.

/** 法二. Using the `in` operator*/
//表达式为: n in x
//n is a string literal or string literal type and x is a union type
//the “true” branch narrows to types which have an optional or required property n
//and the “false” branch narrows to types which have an optional or missing property n
if("swim" in pet){
  pet.swim()
}else{
  pet.fly();
}


let c: unknown = 1;
function isFunction(val:any):val is ()=>void {
  return typeof val === 'function';
}
if(isFunction(c)){
  c();
}
